﻿using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using LimaLims.Application.Service.Cache;
using LimaLims.Core;
using LimaLims.Core.Entity.System;
using LimaLims.Core.Enum;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Xml.Linq;
using Yitter.IdGenerator;

namespace LimaLims.Application.Service.Role
{
    /// <summary>
    /// 角色服务
    /// </summary>
    [ApiDescriptionSettings(Name = "Role", Order = 149)]
    [Route("api")]
    public class SysRoleService : ISysRoleService, IDynamicApiController, ITransient
    {
        private readonly IRepository<SysRole> _sysRoleRep;  // 角色表仓储
        private readonly IRepository<SysUserRole> _sysUserRoleRep;  // 用户角色表仓储
        private readonly IRepository<SysRoleMenu> _sysRoleMenuRep;// 角色菜单表仓储
        private readonly IRepository<SysMenu> _sysMenuRep;  // 菜单表仓储
        private readonly ISysCacheService _sysCacheService;
        private readonly ISysRoleMenuService _sysRoleMenuService;
        public SysRoleService(IRepository<SysRole> sysRoleRep, IRepository<SysUserRole> sysUserRoleRep, IRepository<SysRoleMenu> sysRoleMenuRep, IRepository<SysMenu> sysMenuRep, ISysCacheService sysCacheService, ISysRoleMenuService sysRoleMenuService)
        {
            _sysRoleRep = sysRoleRep;
            _sysUserRoleRep = sysUserRoleRep;
            _sysRoleMenuRep = sysRoleMenuRep;
            _sysMenuRep = sysMenuRep;
            _sysCacheService = sysCacheService;
            _sysRoleMenuService = sysRoleMenuService;
        }

        [HttpPost("sysRole/add")]
        [UnitOfWork]
        public async Task AddRole(AddRoleInput input)
        {
            var isExist = await _sysRoleRep.DetachedEntities.AnyAsync(u => u.Code == input.Code || u.Name == input.Name);
            if (isExist)
                throw Oops.Oh("角色名称或者角色标识已存在");

            input.Id = YitIdHelper.NextId();
            var role = input.Adapt<SysRole>();
            await role.InsertAsync();
            await UpdateRoleMenu(input);
        }

        /// <summary>
        /// 删除角色
        /// </summary>
        /// <param name="roleId"></param>
        /// <returns></returns>
        [HttpPost("sysRole/delete")]
        [UnitOfWork]
        public async Task DeleteRole(long roleId)
        {
            var sysRole = await _sysRoleRep.FirstOrDefaultAsync(u => u.Id == roleId);
            if (sysRole == null)
                throw Oops.Oh("不存在此数据");

            await sysRole.DeleteAsync();

            //级联删除该角色对应的用户-角色表关联信息
            var userRoles = await _sysUserRoleRep.Where(u => u.SysRoleId == sysRole.Id).ToListAsync();
            await _sysUserRoleRep.DeleteAsync(userRoles);

            //级联删除该角色对应的角色-菜单表关联信息
            var roleMenus = await _sysRoleMenuRep.DetachedEntities.Where(u => u.SysRoleId == roleId).ToListAsync();
            await _sysRoleMenuRep.DeleteAsync(roleMenus);
        }

        /// <summary>
        /// 角色下拉
        /// </summary>
        /// <returns></returns>
        [HttpGet("sysRole/dropDown")]
        public async Task<List<RoleOutput>> GetRoleDropDown()
        {
            var roleIds = new List<long>();
            // 如果不是超级管理员，则查询自己拥有的角色集合

            if (CurrentUserInfo.IsSuperAdmin)
            {
                roleIds = await _sysRoleRep.DetachedEntities.Where(u => u.ValidStatus).Select(u => u.Id).ToListAsync();
            }
            else
            {
                roleIds = await _sysUserRoleRep.Where(u => u.SysUserId == CurrentUserInfo.UserId).Select(u => u.SysRoleId).ToListAsync();
            }


            return await _sysRoleRep.DetachedEntities.Where(roleIds.Count > 0, u => roleIds.Contains(u.Id))
                                    .Where(u => u.ValidStatus).ProjectToType<RoleOutput>().ToListAsync();
        }

        [NonAction]
        public async Task<dynamic> GetRoleList([FromQuery] RoleInput input)
        {
            var name = !string.IsNullOrEmpty(input.Name?.Trim());
            var code = !string.IsNullOrEmpty(input.Code?.Trim());
            return await _sysRoleRep.DetachedEntities
                                    .Where((name, u => EF.Functions.Like(u.Name, $"%{input.Name.Trim()}%")),
                                           (code, u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%")))
                                    .Where(u => u.ValidStatus)
                                    .OrderBy(u => u.Sort)
                                    .Select(u => new
                                    {
                                        u.Id,
                                        Name = u.Name + "[" + u.Code + "]",
                                    })
                                    .ToListAsync();
        }

        /// <summary>
        /// 根据菜单权限标识获取用户ID
        /// </summary>
        /// <param name="permission">权限标识</param>
        /// <returns></returns>
        [NonAction]
        public async Task<List<long>> GetUsersByMenuPermission(string permission)
        {
            List<long> UserIds= new List<long>();
            var menu = await _sysMenuRep.DetachedEntities.FirstOrDefaultAsync(s => s.Permission.Equals(permission));
            if (menu == null)
            {
                throw Oops.Oh("不存在此权限数据");
            }

            var roleIds = _sysRoleMenuRep.DetachedEntities.Where(s => s.SysMenuId == menu.Id).Select(s => s.SysRoleId).Distinct();

            UserIds =await _sysUserRoleRep.DetachedEntities.Where(s => roleIds.Contains(s.SysRoleId)).Select(s=>s.SysUserId).Distinct().ToListAsync();

            return UserIds;
        }
        /// <summary>
        /// 获取用户角色相关信息（登录）
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        [NonAction]
        public async Task<List<RoleOutput>> GetUserRoleList(long userId)
        {
            return await _sysUserRoleRep.Include(m => m.SysRole, false)
                 .Where(m => m.SysUserId == userId && m.SysRole.ValidStatus)
                 .Select(m => new RoleOutput
                 {
                     Id = m.SysRoleId,
                     Code = m.SysRole.Code,
                     Name = m.SysRole.Name
                 }).ToListAsync();
        }

        /// <summary>
        /// 获取角色以及拥有菜单Id集合
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("sysRole/detail")]
        public async Task<QueryRoleOutput> Detail([FromQuery] QueryRoleInput input)
        {
            var role = await _sysRoleRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Id);

            var sysRole = role.Adapt<QueryRoleOutput>();

            var menus = await _sysRoleMenuService.GetRoleMenuIdList(new List<long> { input.Id });

            sysRole.MenuIdList = menus;

            return sysRole;
        }

        /// <summary>
        /// 角色获取分页
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("sysRole/page")]
        public async Task<PageResult<SysRole>> QueryRolePageList([FromQuery] RolePageInput input)
        {
            var name = !string.IsNullOrEmpty(input.Name?.Trim());
            var code = !string.IsNullOrEmpty(input.Code?.Trim());
            var roles = await _sysRoleRep.DetachedEntities
                                         .Where((name, u => EF.Functions.Like(u.Name, $"%{input.Name.Trim()}%")),
                                                (code, u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%")))
                                         .OrderBy(u => u.Sort)
                                         .ToADPagedListAsync(input.PageNo, input.PageSize);
            return roles;
        }

        /// <summary>
        /// 更新角色
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("sysRole/edit")]
        [UnitOfWork]
        public async Task UpdateRole(UpdateRoleInput input)
        {
            var adminRole = await _sysRoleRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Id);
            if (adminRole == null)
                throw Oops.Oh("不存在此数据！");

            var isExist = await _sysRoleRep.DetachedEntities.AnyAsync(u => (u.Name == input.Name || u.Code == input.Code) && u.Id != input.Id);
            if (isExist)
                throw Oops.Oh("角色名称和标识不能重复，请重新填写！");

            var sysRole = input.Adapt<SysRole>();

            await sysRole.UpdateAsync();

            await UpdateRoleMenu(input);
        }

        /// <summary>
        /// 更新角色菜单权限
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private async Task UpdateRoleMenu(AddRoleInput input)
        {
            if (input.MenuIdList == null || input.MenuIdList.Count < 1)
                return;

            var roleMenus = await _sysRoleMenuRep.DetachedEntities.Where(u => u.SysRoleId == input.Id).ToListAsync();

            await _sysRoleMenuRep.DeleteAsync(roleMenus);

            // 将父节点为0的菜单排除，防止前端全选异常
            //var pMenuIds = await _sysMenuRep.DetachedEntities.Where(u => input.MenuIdList.Contains(u.Id) && u.Pid == 0).Select(S => S.Id).ToListAsync();

            // var menuIds = input.MenuIdList.Except(pMenuIds); // 差集

            var menus = input.MenuIdList.Select(u => new SysRoleMenu
            {
                SysRoleId = input.Id,
                SysMenuId = u
            }).ToList();

            await _sysRoleMenuRep.InsertAsync(menus);

            // 清除缓存
            await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_MENU);
            await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_PERMISSION);

        }
    }
}
